package com.atguigu.rabbit.producer.config;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 自定义RabbitTemplate
 *
 * @author Taeyang
 */
@Configuration
public class RabbitTemplateConfiguration {

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {

        // 创建一个rabbitTemplate对象
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);

        //////////////////////////////////// confirm 生产者确认机制 ////////////////////////////////////

        // 绑定生产者确认机制的回调函数（Lambda 写法）
        // correlationData：封装了消息数据，包含唯一id
        // ack：交换机是否接收到消息的确认字符
        // cause：交换机拒绝接收消息的原因
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            // 获取当前消息的id：
            String msgId = correlationData.getId();
            if (ack) {
                System.out.println("消息成功发送给交换机，交换机返回确认ack");
                // TODO：根据这个msgId修改MySQL数据库中当前消息的消息状态
            } else {
                System.out.println("消息发送给交换机失败，msgId = " + msgId);
                System.out.println("失败原因，causer = " + cause);
                // TODO：
                // 根据这个msgId从MySQL数据库中查询出当前消息的记录
                // 判断定义的重试次数是否和已重试次数相等，如果已重试次数<定义的重试次数，那么就重发
                // 否则不重发
                // 根据这个记录重新发送消息：rabbitTemplate.convertAndSend(动态参数);
            }
        });

        //////////////////////////////////// return 生产者回退机制 ////////////////////////////////////

        // 让rabbitmq将失败的消息的信息再次返回给生产者
        rabbitTemplate.setMandatory(true);

        // 绑定生产者回退机制回调函数
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            @Override
            public void returnedMessage(ReturnedMessage returnedMessage) {
                Message message = returnedMessage.getMessage();
                System.out.println("消息由路由投递给消息队列失败， msg ---> " + message);
                System.out.println("message body " + message.getBody());
                System.out.println("message properties " + message.getMessageProperties());
                Object msgId = message.getMessageProperties().getHeader("spring_returned_message_correlation");
                System.out.println("获取的消息id = " + msgId);
                // TODO 根据msgId从MySQL数据库中获取消息记录，一边重新发送
                System.out.println("message class " + message.getClass());
                System.out.println("交换机 exchange ---> " + returnedMessage.getExchange());
                System.out.println("路由键 routingKey ---> " + returnedMessage.getRoutingKey());
                System.out.println("响应码 replyCode ---> " + returnedMessage.getReplyCode());
                System.out.println("响应消息 replyText ---> " + returnedMessage.getReplyText());
            }
        });

        return rabbitTemplate;
    }
}